This introduction notebook illustrates how to mask potentially spurious inactivity periods.
First, load the pyActigraphy package:
In [1]:
import pyActigraphy
/usr/local/lib/python3.7/site-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
import pandas.util.testing as tm
As well as your favourite plotting package:
In [2]:
import plotly.graph_objs as go
As an example, let’s read a .awd file located in the test directory of the pyActigraphy package:
In [3]:
import os
fpath = os.path.join(os.path.dirname(pyActigraphy.__file__),'tests/data/')
In [4]:
raw = pyActigraphy.io.read_raw_awd(fpath+'example_01_mask.AWD')
In [5]:
layout = go.Layout(title="Actigraphy data", xaxis=dict(title="Date time"), yaxis=dict(title="Counts/period"), showlegend=False)
In [6]:
go.Figure(data=go.Scatter(x=raw.data.index.astype(str), y=raw.data), layout=layout)
At first sight, it seems that there is a suspicious period of total inactivity (activity counts equal to zero), starting at 9h30 on the 27th of January.
It seems spurious for several reasons:
it happens outside the usually sleep time window (although a nap might be possible…);
it consists of a long series of consecutive “total” inactivity (i.e. zero count) while other potential sleep periods do not;
it exhibits a sharp decrease of activity with respect to the surrounding time periods;
Most likely, it corresponds to a period where the actigraph has been removed by the participant.
While it is fairly (although not totally) simple to deal with inactivity periods at the beginning and at the end of the recordings (cf this other tutorial notebook), it is more difficult to deal, in an automatic fashion, with inactivity periods happening during the recording.
Fortunately, the pyActigraphy package offers a simple way to deal with these periods by masking the corresponding data.
Spurious inactivity periods are defined as series of consecutive zeros. The lenght of these series is configurable.
In [7]:
raw.frequency
Out[7]:
Timedelta('0 days 00:01:00')
In [8]:
# The duration corresponds either to the minimal number of inactive epochs (ex: duration=120)
# or the minimal length of the inactive period (duration='2h00min')
raw.create_inactivity_mask(duration='2h00min')
In [9]:
raw.inactivity_length
Out[9]:
120
WARNING: Creating a mask does not mean it is applied. Cf. next section.
Before applying it, let’s visualize it:
In [10]:
layout = go.Layout(title="Data mask", xaxis=dict(title="Date time"), yaxis=dict(title="Mask"), showlegend=False)
In [11]:
go.Figure(data=go.Scatter(x=raw.mask.index.astype(str),y=raw.mask),layout=layout)
Periods in the data for which the mask is equal to zero will be masked (once the mask is applied).
As expected, the spurious period of total inactivity of the 27th of January has been found by the pyActigraphy package and therefore can be masked upon request (cf. next section).
Once a mask has been created, it is possible to dynamically change the configuration of its minimal duration:
In [12]:
raw.inactivity_length = '4h'
In [13]:
go.Figure(data=go.Scatter(x=raw.mask.index.astype(str),y=raw.mask),layout=layout)
Masking the spurious inactivity periods is crucial as it can substantially affect the calculation of the rest-activity rhythm related variables.
For example:
Applying the mask is controlled by the following variable:
In [14]:
raw.mask_inactivity = True
In [15]:
raw.IS()
Out[15]:
0.5754713250134655
Interesting, isn’t it?
Besides, the application of the masking is dynamic:
In [16]:
raw.mask_inactivity = False
In [17]:
raw.IS()
Out[17]:
0.4453375595033997
A last word; be cautious when masking your data. Series of consecutive periods of total inactivity might happen during sleep… A visual check of the mask is always a good idea.